//卡牌类型
import ResLoader from "../../Core/Libs/ResLoader";
import CardLib from "./CardLib";

export enum CardType {
    Hero = 1, //主角
    Boss, //boss
    Monster,//怪物
    Health, //恢复类道具
    Skill,//技能
    Treasure,//宝箱
    Trap,//陷阱
    Shield,//护身法宝
    Coin,//货币
}

//移动方向
export enum Direction {
    UP = 1, //上
    Right, //右
    Down,//下
    Left, //左
}

export enum DirectionMode {
    Forward = 1, //正前方
    Behind, //正后方
    Clockwise,//顺时针
    AntiClockwise, //逆时针
}

//卡牌详情
export interface CardInfo {
    type: CardType,
    id: number,
    value: number,
    maxValue?: number,
}

//格子详情
export interface GridInfo {
    positionX: number,
    positionY: number,
    cardInfo: CardInfo | null,
    node: cc.Node | null,
    index: string,
    vec2: cc.Vec2
}

export class GridsLib {
    public wrapNode: cc.Node
    public allGrids: Map<string, GridInfo> = new Map();

    public itemNodeAttr = {
        width: 220,
        height: 300,
        spacingRight: 20,
        spacingBottom: 20
    }

    public readyMoveGirdIndexMap: Map<string, string> = new Map()

    constructor(wrapNode) {
        this.wrapNode = wrapNode
    }

    //设置格子属性
    public setGridItemAttr(width: number, height: number, spacingRight: number = 20, spacingBottom: number = 20) {
        this.itemNodeAttr.width = width;
        this.itemNodeAttr.height = height;
        this.itemNodeAttr.spacingRight = spacingRight;
        this.itemNodeAttr.spacingBottom = spacingBottom;
    }

    //生成格子
    public async generateGrids(rows: number, cells: number) {

        //重新定义卡牌高宽
        this.itemNodeAttr.width = (this.wrapNode.width - this.itemNodeAttr.spacingRight * (cells - 1)) / cells
        this.itemNodeAttr.height = (this.wrapNode.height - this.itemNodeAttr.spacingBottom * (rows - 1)) / rows


        //定义一个纯色背景
        // let sp = this.wrapNode.addComponent(cc.Sprite)
        // sp.spriteFrame = this.generateSpriteFrame(20, 50, 100, this.wrapNode.width, this.wrapNode.height)

        // //居中
        // let widget = this.wrapNode.addComponent(cc.Widget)
        // widget.horizontalCenter = 0;


        //生成子节点
        for (let i = 0; i < rows; i++) {
            this.allGrids[i] = [];
            for (let k = 0; k < cells; k++) {
                let itemNode = await this.newGridItem();

                //初始坐标
                let positionX = -this.wrapNode.width / 2 + this.itemNodeAttr.width / 2,
                    positionY = -this.wrapNode.height / 2 + this.itemNodeAttr.height / 2;

                //
                if (i > 0) {
                    positionY += i * this.itemNodeAttr.height + i * this.itemNodeAttr.spacingBottom
                }

                if (k > 0) {
                    positionX += k * this.itemNodeAttr.width + k * this.itemNodeAttr.spacingRight
                }

                itemNode.setPosition(positionX, positionY * -1);
                this.wrapNode.addChild(itemNode)


                //保存grid
                let index = i + "-" + k
                this.allGrids.set(
                    index,
                    <GridInfo>{
                        positionX: itemNode.x,
                        positionY: itemNode.y,
                        node: itemNode,
                        cardInfo: null,
                        index: index,
                        vec2: cc.v2(i, k)
                    }
                )
            }
        }

    }

    private async newGridItem(): Promise<cc.Node> {

        let prefabAsset: cc.Prefab = await ResLoader.load("prefab/card", cc.Prefab)
        let cardNode: cc.Node = cc.instantiate(prefabAsset)

        cardNode.getComponent(CardLib).init(this.itemNodeAttr.width,this.itemNodeAttr.height)

        //默认先隐藏
        cardNode.active = false;
        return cardNode;
    }

    public generateSpriteFrame(r, g, b, w, h): cc.SpriteFrame {
        let texture = new cc.Texture2D();
        let spriteFrame = new cc.SpriteFrame();

        let imgData = new Uint8Array(4);
        for (let j = 0; j < 4; j += 4) {
            imgData[j] = r // r
            imgData[j + 1] = g // g
            imgData[j + 2] = b // b
            imgData[j + 3] = 255 // a
        }

        texture.initWithData(imgData, cc.Texture2D.PixelFormat.RGBA8888, 1, 1);
        spriteFrame.setTexture(texture);
        spriteFrame.setRect(cc.rect(0, 0, w, h));
        return spriteFrame
    }

    public getAllGrids() {
        return this.allGrids;
    }


    //设置卡牌
    public async setGridsCard(cards: CardInfo[]) {
        if (this.allGrids.size == 0) {
            return;
        }

        let allGridsArray = Array.from(this.allGrids.values());
        for (let gridInfo of allGridsArray) {
            await this.setCardOnGrid(cards.shift(), gridInfo)
        }
    }

    //设置单张卡在指定坐标上
    public async setCardOnGrid(cardInfo: CardInfo, grid: GridInfo, asyncTween:boolean = false) {
        if (!cardInfo) {
            return;
        }


        let cardScript: CardLib = grid.node.getComponent(CardLib)
        await cardScript.setCardAttr(cardInfo)

        grid.node.active = true;
        grid.cardInfo = cardInfo

        let d = 0.1;
        let tween = cc.tween(grid.node).sequence(
            cc.tween().to(d, {scaleX: 0, scaleY: 1, skewX: 0, skewY: 2}),
            cc.callFunc(() => {
                cardScript.cardFront.active = true;
                cardScript.cardBack.active = false;
                grid.node.skewY = -2;
            }),
            cc.tween().to(d, {scaleX: 1, scaleY: 1, skewX: 0, skewY: 0}),
        )

        //异步的 就相当于 以前翻牌
        if(asyncTween){
            tween.start();
        }
        //同步的 就等前面翻完再翻下一张
        else{
            await new Promise<void>((resolve) => {
                tween.call(resolve).start()
            })
        }

    }

    //注册节点事件
    public registerClickEvent(callback, bind) {
        this.allGrids.forEach(grid => {
            grid.node.on(cc.Node.EventType.TOUCH_END, callback, bind)
        })
    }


    //通过卡牌类型 获取块信息
    public getGridInfoByCardType(type: CardType): GridInfo[] {
        let result: GridInfo[] = [];
        this.allGrids.forEach(info => {
            if (info.cardInfo && info.cardInfo.type == type) {
                result.push(info)
            }
        })

        return result;
    }

    public getGridInfoByIndex(index: string): GridInfo | null {
        return this.allGrids.get(index) || null;
    }

    public getGridInfoByDirection(index: string, direction: Direction, mode: DirectionMode = DirectionMode.Forward): GridInfo | null {
        direction = this.changeDirection(direction, mode);
        return this.allGrids.get(this.getDirectionIndex(index, direction)) || null;
    }

    public getGridInfoByNode(node: cc.Node): GridInfo | null {
        let result: GridInfo = null
        this.allGrids.forEach(info => {
            if (info.node.uuid == node.uuid) {
                result = info;
                return false;
            }
        })

        return result;
    }

    //获取一个方向上的所有grid
    public getAllGridsInfoByDirection(index: string, direction: Direction, mode: DirectionMode = DirectionMode.Forward): GridInfo[] {
        direction = this.changeDirection(direction, mode);

        let result: GridInfo[] = [];

        while (true) {
            let gridInfo = this.allGrids.get(this.getDirectionIndex(index, direction))
            if (!gridInfo) {
                break;
            }
            result.push(gridInfo)
            index = gridInfo.index
        }

        return result;
    }


    //获取方向的其他方向
    public changeDirection(direction: Direction, mode: DirectionMode): Direction {

        if (mode == DirectionMode.Forward) {
            return direction;
        }

        //当前方向的反方向
        if (mode == DirectionMode.Behind) {
            switch (direction) {
                case Direction.UP:
                    return Direction.Down;
                case Direction.Left:
                    return Direction.Right;
                case Direction.Right:
                    return Direction.Left;
                case Direction.Down:
                    return Direction.UP
            }
        }

        //当前方向的顺时针方向 / 逆时针方向
        if (mode == DirectionMode.Clockwise || mode == DirectionMode.AntiClockwise) {
            if (mode == DirectionMode.Clockwise) {
                direction += 1;
            }
            //逆时针
            else {
                direction -= 1;
            }

            if (direction < 1) {
                direction = 4;
            } else if (direction > 4) {
                direction = 1
            }

            return direction;
        }
    }


    //获取指定方向的索引
    public getDirectionIndex(index: string, direction: Direction): string {
        let curIndex = index.split("-").map(Number)
        switch (direction) {
            case Direction.UP:
                curIndex[0] -= 1
                break;
            case Direction.Down:
                curIndex[0] += 1
                break;
            case Direction.Left:
                curIndex[1] -= 1
                break;
            case Direction.Right:
                curIndex[1] += 1
                break;
        }

        return curIndex.join("-")
    }

    //注册准备移动的队列
    public joinMoveQueue(fromIndex: string, toIndex: string) {
        this.readyMoveGirdIndexMap.set(toIndex, fromIndex)
    }

    public async startMove(moveList: GridInfo[]): Promise<GridInfo> {
        if (moveList.length == 0) {
            return null;
        }

        let tweenArray: Promise<void>[] = []
        moveList.forEach((fromGridInfo, k) => {
            //第一个跳过并隐藏
            if (k == 0) {
                fromGridInfo.node.active = false;
                return true;
            }

            //目标节点是 当前索引前一个
            let targetGridInfo = moveList[k - 1]

            let tween = new Promise<void>((resolve) => {
                cc.tween(fromGridInfo.node).to(0.3,
                    {x: targetGridInfo.positionX, y: targetGridInfo.positionY}
                ).call(() => {
                    resolve();
                }).start()
            })

            tweenArray.push(tween)
        })

        return await Promise.all(tweenArray).then(() => {
            //移动后覆盖格子值
            moveList.forEach((targetGridInfo, k) => {

                let fromGridInfo: GridInfo
                //最后一个的节点  用第一个节点补充
                if (k == moveList.length - 1) {
                    fromGridInfo = moveList[0]

                    //这里把第一个节点的位置 移动到最后一个节点的位置上
                    fromGridInfo.node.x = targetGridInfo.positionX;
                    fromGridInfo.node.y = targetGridInfo.positionY;

                } else {
                    fromGridInfo = moveList[k + 1]
                }

                //从缓存副本取值
                this.allGrids.set(targetGridInfo.index, {
                    positionX: targetGridInfo.positionX,
                    positionY: targetGridInfo.positionY,
                    node: fromGridInfo.node,
                    cardInfo: fromGridInfo.cardInfo,
                    index: targetGridInfo.index,
                    vec2: targetGridInfo.vec2
                })
            })

            //返回需要补卡的节点
            return this.allGrids.get(moveList[moveList.length - 1].index)
        })

    }
}